//////////////////////////////////////////////////////////////////////////
#pragma once


//////////////////////////////////////////////////////////////////////////
#include <Math/Math.hpp>


//////////////////////////////////////////////////////////////////////////
// Reference version is always available.
#include "Math/SIMD/Reference/Reference.hpp"


//////////////////////////////////////////////////////////////////////////
// We only need to support a subset of the SSE variations since some
// variations contain no useful math instructions for our goals.
// NOTE: In the future SSE2 may be desirable to support double based
// types but for now we ignore it.


//////////////////////////////////////////////////////////////////////////
// Simd versions available on Intel platforms.  NOTE:  All versions are
// available up to AVX, only usage will fail if the CPU does not support
// the instructions.  Exception to this is on Os X where the headers trim
// back on the available intrinsics based on compiler settings.
#if !defined( SIMD_NEON )

#	if __APPLE__
		// Make sure the following items are defined if supported:
		//	__MMX__ __SSE__ __SSE2__ __SSE3__ __SSSE3__ __SSE4_2__ __SSE4_1__ __AVX__ __AVX2__
		// And some others we won't be using.
#		include <AvailabilityMacros.h>
#	endif
	// Intel SSE supported.  Include up to AVX support.
	// NOTE: VC allows compiling the code even though the instructions are
	// not available on the compiling machine, Os X Mountain Lion will not
	// allow inclusion of the intrinsics unless the compiler is set to
	// support them, so you have to check the definitions above for type
	// and intrinsic availability.
#	include <immintrin.h>

#	if __APPLE__
#		if ( defined( __AVX2__ ) || defined( __AVX__ ) ) && defined( SIMD_SSE_AVX )
#			include <Math/Simd/Sse/Avx.hpp>
#			define Simd_t	Math::Simd::Avx
#		elif ( defined( __SSE4_2__ ) || defined( __SSE4_1__ ) ) && defined( SIMD_SSE_4 )
#			include <Math/Simd/Sse/Sse4.hpp>
#			define Simd_t	Math::Simd::Sse4
#		elif ( defined( __SSSE3__ ) || defined( __SSE3__ ) ) && defined( SIMD_SSE_3 )
#			include <Math/Simd/Sse/Sse3.hpp>
#			define Simd_t	Math::Simd::Sse3
#		elif ( defined( __SSE__ ) || defined( __SSE2__ ) ) && defined( SIMD_SSE )
#			include <Math/Simd/Sse/Sse1.hpp>
#			define Simd_t	Math::Simd::Sse
#		else
#			define Simd_t	Math::Simd::Reference
#		endif
#	else
		// Support all variations as targets on VC.  But select our
		// desired target level based on build settings.
#		include <Math/Simd/Sse/Avx.hpp>
#		if defined( SIMD_SSE_AVX )
#			define Simd_t	Math::Simd::Avx
#		elif defined( SIMD_SSE_4 )
#			define Simd_t	Math::Simd::Sse4
#		elif defined( SIMD_SSE_3 )
#			define Simd_t	Math::Simd::Sse3
#		elif defined( SIMD_SSE )
#			define Simd_t	Math::Simd::Sse
#		else
#			define Simd_t	Math::Simd::Reference
#		endif
#	endif

//////////////////////////////////////////////////////////////////////////
// iDevice targets.
#elif !defined( TARGET_IPHONE_SIMULATOR )

	// NEON supported.
#	include <arm_neon.h>
#	include "Math/Simd/Neon/Neon.hpp"
#	define Simd_t	Math::Simd::Neon

#else	// !TARGET_IPHONE_SIMULATOR

#	define Simd_t	Math::Simd::Reference;

#endif	// SIMD_NEON


//////////////////////////////////////////////////////////////////////////
// Notes about the Intel headers, not all available on Os X, just include
// the highest possible support and the headers figure out which to
// enable.
/*
#include <immintrin.h>	// AVX intrinsics.  256 bit types for 8xfloat etc.
#include <wmmintrin.h>	// AES & PCLMULQDQ intrinsics.
#include <nmmintrin.h>	// Core 2 Duo SSE4.2 intrinsics.  String and CRC calculations mostly.
#include <smmintrin.h>	// Core 2 Duo SSE4.1 intrinsics.  Advanced math ceil/floor, and insert/extract of lanes.
#include <tmmintrin.h>	// SSSE3 intrinsics.  SSE3.1  Horizontal support for integer types.
#include <pmmintrin.h>	// SSE3 intrinsics.  Primary support of floating point horizontal instructions.
#include <emmintrin.h>	// Willamette intrinsics.  SSE2.  Primarily double pair instructions.
#include <xmmintrin.h>	// SSE1 types.  Basic SIMD intrinsics for 4xfloat etc.
#include <mmintrin.h>	// MMX intrinsics + 64 bit types.
*/
